package com.atguigu.ai.functioncall.service;

import com.fasterxml.jackson.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Description;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Base64;
import java.util.function.Function;

@Service
@Description("天气查询服务 - 可以查询指定城市的天气情况和温度")
@JsonClassDescription("天气查询服务")
public class WeatherService implements Function<WeatherService.Request, WeatherService.Response> {

    private static final Logger logger = LoggerFactory.getLogger(WeatherService.class);

    // 和风天气API接口地址
    private static final String WEATHER_API_URL = "https://p75ctu5fyt.re.qweatherapi.com/v7/weather/now";
    private static final String GEO_API_URL = "https://p75ctu5fyt.re.qweatherapi.com/geo/v2/city/lookup";

    @Value("${weather.api.key:}")
    private String apiKey;

    @Value("${weather.jwt.token:}")
    private String jwtToken;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public Response apply(Request request) {
        try {
            if ((apiKey == null || apiKey.trim().isEmpty()) && (jwtToken == null || jwtToken.trim().isEmpty())) {
                logger.error("天气API密钥和JWT Token都未配置");
                return new Response(request.city(), "API认证未配置", 0, "配置错误", "未知", "未知");
            }

            return getRealWeatherData(request.city());
        } catch (Exception e) {
            logger.error("获取天气数据失败: {}", e.getMessage(), e);
            return new Response(request.city(), "获取天气数据失败: " + e.getMessage(), 0, "错误", "未知", "未知");
        }
    }

    private Response getRealWeatherData(String city) {
        try {
            // 1. 获取城市ID
            String locationId = getCityLocationId(city);
            if (locationId == null) {
                return new Response(city, "未找到该城市", 0, "城市不存在", "未知", "未知");
            }

            // 2. 构建天气查询URL（使用key参数）
            String weatherUrl = UriComponentsBuilder.fromHttpUrl(WEATHER_API_URL)
                    .queryParam("location", locationId)
                    .queryParam("key", apiKey)
                    .build()
                    .toUriString();

            logger.info("正在查询天气数据: {}", weatherUrl.replace(apiKey, "***"));

            // 3. 发送天气查询请求
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            // 3. 创建HttpEntity
            HttpEntity<String> requestEntity = new HttpEntity<>(headers);
            ResponseEntity<WeatherApiResponse> responseEntity = restTemplate.exchange(
                    weatherUrl,
                    HttpMethod.GET,
                    requestEntity,
                    WeatherApiResponse.class
            );
            System.out.println(responseEntity);
            WeatherApiResponse response = responseEntity.getBody();

            // 4. 处理响应
            if (response != null) {
                if ("200".equals(response.code)) {
                    WeatherApiResponse.Now now = response.now;
                    String weatherDesc = String.format("%s，温度%s°C，体感温度%s°C，%s%s级，相对湿度%s%%",
                            now.text,
                            now.temp,
                            now.feelsLike,
                            now.windDir,
                            now.windScale,
                            now.humidity);

                    return new Response(
                            city,
                            weatherDesc,
                            Integer.parseInt(now.temp),
                            now.text,
                            now.humidity + "%",
                            now.windDir + " " + now.windScale + "级"
                    );
                } else {
                    logger.warn("天气API返回错误码: {}", response.code);
                    return new Response(city, "天气API返回错误: " + response.code, 0, "API错误", "未知", "未知");
                }
            } else {
                return new Response(city, "天气API返回空响应", 0, "API错误", "未知", "未知");
            }
        } catch (Exception e) {
            logger.error("获取天气数据异常: {}", e.getMessage(), e);
            return new Response(city, "获取天气数据异常: " + e.getMessage(), 0, "系统错误", "未知", "未知");
        }
    }

    /**
     * 根据和风天气官方文档获取城市位置ID
     * 使用JWT认证方式调用城市搜索API
     */
    private String getCityLocationId(String city) {
        try {
            String jwtToken = getJwtToken();
            // 1. 构建城市查询URL（不包含key参数，使用JWT认证）
            String geoUrl = UriComponentsBuilder.fromHttpUrl(GEO_API_URL)
                    .queryParam("location", city)
                    .queryParam("number", "1")  // 只返回最相关的一个结果
                    .build()
                    .toUriString();

            logger.info("正在查询城市信息: {}", geoUrl);

            // 2. 创建请求头，设置JWT认证
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(jwtToken);
            headers.setContentType(MediaType.APPLICATION_JSON);
            // 3. 创建HttpEntity
            HttpEntity<String> requestEntity = new HttpEntity<>(headers);

            // 4. 发送请求
            ResponseEntity<GeoApiResponse> responseEntity = restTemplate.exchange(
                    geoUrl,
                    HttpMethod.GET,
                    requestEntity,
                    GeoApiResponse.class
            );

            System.out.println(responseEntity);
            GeoApiResponse response = responseEntity.getBody();
            // 5. 处理响应
            if (response != null && "200".equals(response.code)) {
                if (response.location != null && !response.location.isEmpty()) {
                    GeoApiResponse.Location location = response.location.get(0);
                    logger.info("找到城市: {} -> ID: {}, 名称: {}, 地区: {}/{}",
                            city, location.id, location.name, location.adm1, location.adm2);
                    return location.id;
                }
            }

            logger.warn("未找到城市: {}, API响应码: {}", city, response != null ? response.code : "null");
            return null;

        } catch (Exception e) {
            logger.error("查询城市信息异常: {}", e.getMessage(), e);
            return null;
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class WeatherApiResponse {
        public String code;
        public String updateTime;
        public String fxLink;
        public Now now;

        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class Now {
            public String obsTime;     // 数据观测时间
            public String temp;        // 温度，默认单位：摄氏度
            public String feelsLike;   // 体感温度，默认单位：摄氏度
            public String icon;        // 天气状况图标代码
            public String text;        // 天气状况描述
            public String wind360;     // 风向360角度
            public String windDir;     // 风向
            public String windScale;   // 风力等级
            public String windSpeed;   // 风速，公里/小时
            public String humidity;    // 相对湿度，百分比数值
            public String precip;      // 当前小时累计降水量，默认单位：毫米
            public String pressure;    // 大气压强，默认单位：百帕
            public String vis;         // 能见度，默认单位：公里
            public String cloud;       // 云量，百分比数值
            public String dew;         // 露点温度，默认单位：摄氏度
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class GeoApiResponse {
        public String code;
        public java.util.List<Location> location;

        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class Location {
            public String name;        // 地区/城市名称
            public String id;          // 地区/城市ID
            public String lat;         // 纬度
            public String lon;         // 经度
            public String adm2;        // 地区/城市的上级行政区划名称
            public String adm1;        // 地区/城市所属一级行政区划名称
            public String country;     // 地区/城市所属国家名称
            public String tz;          // 地区/城市所在时区
            public String utcOffset;   // 地区/城市目前与UTC时间偏移的小时数
            public String isDst;       // 地区/城市是否当前处于夏令时
            public String type;        // 地区/城市的属性
            public String rank;        // 地区评分
            public String fxLink;      // 该地区的天气预报网页链接
        }
    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonClassDescription("天气查询请求参数")
    public record Request(
            @JsonProperty(required = true, value = "city")
            @JsonPropertyDescription("要查询天气的城市名称")
            String city
    ) {
    }

    @JsonClassDescription("天气查询响应结果")
    public record Response(
            String city,           // 查询的城市
            String weather,        // 天气完整描述
            int temperature,       // 温度（摄氏度）
            String condition,      // 天气状况
            String humidity,       // 相对湿度
            String windDirection   // 风向和风力
    ) {
    }

    public String getJwtToken() throws Exception {
        // Private key
        String privateKeyString = "MC4CAQAwBQYDK2VwBCIEIN434nC0yQU64FnRtPYIODfDCt6URLKV5k9Av8LIHINn";
        privateKeyString = privateKeyString.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").trim();
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EdDSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

// Header
        String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"C7H2556Q5J\"}";

// Payload
        long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
        long exp = iat + 900;
        String payloadJson = "{\"sub\": \"3BTMKYF2BF\", \"iat\": " + iat + ", \"exp\": " + exp + "}";

// Base64url header+payload
        String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
        String data = headerEncoded + "." + payloadEncoded;

// Sign
        Signature signer = Signature.getInstance("EdDSA");
        signer.initSign(privateKey);
        signer.update(data.getBytes(StandardCharsets.UTF_8));
        byte[] signature = signer.sign();

        String signatureEncoded = Base64.getUrlEncoder().encodeToString(signature);

        String jwt = data + "." + signatureEncoded;

// Print Token
        System.out.println("Signature:\n" + signatureEncoded);
        System.out.println("JWT:\n" + jwt);
        return jwt;
    }
} 